package com.heima.wemedia.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.aliyun.green20220302.Client;
import com.aliyun.green20220302.models.*;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.teautil.models.RuntimeOptions;
import com.heima.wemedia.bean.ImageCheckResult;
import com.heima.wemedia.bean.TextCheckResult;
import com.heima.wemedia.config.AliYunGreenConfig;
import com.heima.wemedia.service.GreenService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
@Slf4j
public class GreenServiceImpl implements GreenService {

    @Resource
    private AliYunGreenConfig aliYunGreenConfig;

    @Resource
    private Client client;

    //服务是否部署在vpc上
    public static boolean isVPC = false;

    public static Map<String, DescribeUploadTokenResponseBody.DescribeUploadTokenResponseBodyData> tokenMap = new HashMap<>();

    @Override
    public TextCheckResult textCheck(String text) {
        Map<String, Object> params = MapUtil.<String, Object>builder()
                .put("content", text)
                .build();
        TextModerationPlusRequest textModerationPlusRequest = new TextModerationPlusRequest();
        // 检测类型
        textModerationPlusRequest.setService(this.aliYunGreenConfig.getTextService());
        textModerationPlusRequest.setServiceParameters(JSONUtil.toJsonStr(params));

        try {
            TextModerationPlusResponse response = client.textModerationPlus(textModerationPlusRequest);
            if (response.getStatusCode() == 200) {
                TextModerationPlusResponseBody result = response.getBody();
                Integer code = result.getCode();
                if (200 == code) {
                    TextModerationPlusResponseBody.TextModerationPlusResponseBodyData data = result.getData();
                    return TextCheckResult.builder()
                            .riskLevel(data.getRiskLevel())
                            .confidenceList(CollStreamUtil.toList(data.getResult(), TextModerationPlusResponseBody.TextModerationPlusResponseBodyDataResult::getConfidence))
                            .riskWordsList(CollStreamUtil.toList(data.getResult(), TextModerationPlusResponseBody.TextModerationPlusResponseBodyDataResult::getRiskWords))
                            .labelList(CollStreamUtil.toList(data.getResult(), TextModerationPlusResponseBody.TextModerationPlusResponseBodyDataResult::getLabel))
                            .build();
                }
            }
        } catch (Exception e) {
//            e.printStackTrace();
            log.info("文件监测失败，text,{}", text, e);
        }
//        当监测失败的时候，返回一个空值对象，调用方接收到该空值对象，让调用方微服务处理。
        return TextCheckResult.builder().build();
    }

    @Override
    public ImageCheckResult imageCheck(String imagePath) {

        try {
            //注意，此处实例化的client请尽可能重复使用，避免重复建立连接，提升检测性能。

            RuntimeOptions runtime = new RuntimeOptions();

            //本地文件的完整路径，例如D:\localPath\exampleFile.png。
            // String filePath = "F:\\1.jpg";

            String bucketName = null;
            DescribeUploadTokenResponseBody.DescribeUploadTokenResponseBodyData uploadToken = tokenMap.get(this.aliYunGreenConfig.getEndpoint());
            //获取文件上传token
            if (uploadToken == null || uploadToken.expiration <= System.currentTimeMillis() / 1000) {
                DescribeUploadTokenResponse tokenResponse = client.describeUploadToken();
                uploadToken = tokenResponse.getBody().getData();
                bucketName = uploadToken.getBucketName();
            }
            //上传文件请求客户端
            OSS ossClient = getOssClient(uploadToken, isVPC);

            //上传文件
            String objectName = uploadFile(ossClient, imagePath, uploadToken);

            // 检测参数构造。
            Map<String, String> serviceParameters = new HashMap<>();
            //文件上传信息
            serviceParameters.put("ossBucketName", bucketName);
            serviceParameters.put("ossObjectName", objectName);
            serviceParameters.put("dataId", UUID.randomUUID().toString());

            ImageModerationRequest request = new ImageModerationRequest();
            // 图片检测service：内容安全控制台图片增强版规则配置的serviceCode，示例：baselineCheck
            // 支持service请参考：https://help.aliyun.com/document_detail/467826.html?0#p-23b-o19-gff
            request.setService(this.aliYunGreenConfig.getImageService());
//            request.setServiceParameters(JSON.toJSONString(serviceParameters));
            request.setServiceParameters(JSONUtil.toJsonStr(serviceParameters));
            ImageModerationResponse response = null;
            response = client.imageModerationWithOptions(request, runtime);

            // 打印检测结果。
            if (response != null) {
                if (response.getStatusCode() == 200) {
                    ImageModerationResponseBody body = response.getBody();
                    if (body.getCode() == 200) {
                        ImageModerationResponseBody.ImageModerationResponseBodyData data = body.getData();
//                      封装内容即可。
                        return ImageCheckResult.builder()
                                .riskLevel(data.getRiskLevel())
                                .descriptionList(CollStreamUtil.toList(data.getResult(), ImageModerationResponseBody.ImageModerationResponseBodyDataResult::getDescription))
                                .confidenceList(CollStreamUtil.toList(data.getResult(), ImageModerationResponseBody.ImageModerationResponseBodyDataResult::getConfidence))
                                .labelList(CollStreamUtil.toList(data.getResult(), ImageModerationResponseBody.ImageModerationResponseBodyDataResult::getLabel))
                                .build();
                    }
                }
            }

        } catch (Exception e) {
           log.info("图片上传失败, image = {}",imagePath,e);
        }
        return ImageCheckResult.builder().build();
    }


    /**
     * 创建上传文件请求客户端
     *
     * @param tokenData
     * @param isVPC
     */
    private OSS getOssClient(DescribeUploadTokenResponseBody.DescribeUploadTokenResponseBodyData tokenData, boolean isVPC) {
        //注意，此处实例化的client请尽可能重复使用，避免重复建立连接，提升检测性能。
        if (isVPC) {
            return new OSSClientBuilder().build(tokenData.ossInternalEndPoint, tokenData.getAccessKeyId(), tokenData.getAccessKeySecret(), tokenData.getSecurityToken());
        } else {
            return new OSSClientBuilder().build(tokenData.ossInternetEndPoint, tokenData.getAccessKeyId(), tokenData.getAccessKeySecret(), tokenData.getSecurityToken());
        }
    }


    /**
     * 上传文件
     *
     * @param filePath
     * @param tokenData
     * @return
     * @throws Exception
     */
    private String uploadFile(OSS ossClient, String filePath, DescribeUploadTokenResponseBody.DescribeUploadTokenResponseBodyData tokenData) throws Exception {
        String[] split = filePath.split("\\.");
        String objectName;
        if (split.length > 1) {
            objectName = tokenData.getFileNamePrefix() + UUID.randomUUID() + "." + split[split.length - 1];
        } else {
            objectName = tokenData.getFileNamePrefix() + UUID.randomUUID();
        }
        PutObjectRequest putObjectRequest = null;
//      判断是否含 http ，然后做不同的处理。
        if (StrUtil.startWith(filePath, "http")) {
//            处理成inputStream 流
            InputStream inputStream = HttpRequest.get(filePath)
                    .timeout(this.aliYunGreenConfig.getConnectTimeout())
                    .execute()
                    .bodyStream();
            putObjectRequest = new PutObjectRequest(tokenData.getBucketName(), objectName, inputStream);
        } else {
            putObjectRequest = new PutObjectRequest(tokenData.getBucketName(), objectName, new File(filePath));
        }
//        如果是FTP 在做处理。

        ossClient.putObject(putObjectRequest);


        return objectName;
    }
}
